﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Reflection;

namespace NetPE
{
    public partial class CollectionEditor<T> : BaseEditor where T : class, new()
    {
        private class CollectionLinkingBindingList<TMember> : BindingList<TMember>
        {
            public CollectionLinkingBindingList(IList<TMember> coll) : base(coll) {  }

            protected override void ClearItems()
            {
                base.ClearItems();
            }
            protected override void InsertItem(int index, TMember item)
            {
                base.InsertItem(index, item);
            }
            protected override void RemoveItem(int index)
            {
                base.RemoveItem(index);
            }
            protected override void SetItem(int index, TMember item)
            {
                base.SetItem(index, item);
            }
        }

        string n;
        public string PropertyName { get { return n; } set { n = value; } }

        protected SplitContainer can;
        private ListBox sects;
        private BaseEditor etr;

        List<PropertyAction> acts = new List<PropertyAction>();
        public List<PropertyAction> Actions { get { return acts; } }

        public CollectionEditor()
        {
            can = new SplitContainer();
            sects = new ListBox();
            can.Panel1.SuspendLayout();
            can.Panel2.SuspendLayout();
            can.SuspendLayout();
            this.SuspendLayout();

            can.BackColor = Color.White;
            can.Dock = DockStyle.Fill;
            can.Location = new Point(0, 0);

            can.Panel1.Controls.Add(this.sects);

            can.Panel2.BackColor = Color.Black;

            sects.BackColor = Color.Black;
            sects.BorderStyle = BorderStyle.None;
            sects.Dock = DockStyle.Fill;
            sects.ForeColor = Color.White;
            sects.Font = new Font(this.Font.FontFamily, 8);
            sects.IntegralHeight = false;
            sects.DrawMode = DrawMode.OwnerDrawFixed;
            sects.DrawItem += new DrawItemEventHandler(sectsDrawItem);

            if (typeof(T).GetInterface("IList`1") != null && typeof(T).GetInterface("IList`1").GetGenericArguments()[0].IsClass && typeof(T).GetInterface("IList`1").GetGenericArguments()[0].GetConstructor(Type.EmptyTypes) != null)
            {
                etr = Activator.CreateInstance(typeof(CollectionEditor<>).MakeGenericType(typeof(T).GetInterface("IList`1").GetGenericArguments()[0])) as BaseEditor;
                etr.AutoScroll = true;
                etr.BackgroundImageLayout = ImageLayout.None;
                etr.Dock = DockStyle.Fill;
                etr.Font = new Font("Arial", 9);
                can.Panel2.Controls.Add(etr);
            }
            else
            {
                etr = new PropertyEditor();
                etr.AutoScroll = true;
                etr.BackgroundImageLayout = ImageLayout.None;
                etr.Dock = DockStyle.Fill;
                etr.Font = new Font("Arial", 9);
                can.Panel2.Controls.Add(etr);
            }

            Controls.Add(can);
            can.Panel1.ResumeLayout(false);
            can.Panel2.ResumeLayout(false);
            can.ResumeLayout(false);
            this.ResumeLayout(false);

            sects.SelectedIndexChanged += new EventHandler(ItemChanged);
            sects.ContextMenuStrip = new ContextMenuStrip();
            ToolStripMenuItem add = new ToolStripMenuItem("Add");
            add.Click += new EventHandler(Add);
            sects.ContextMenuStrip.Items.Add(add);
            ToolStripMenuItem del = new ToolStripMenuItem("Delete");
            del.Click += new EventHandler(Delete);
            sects.ContextMenuStrip.Items.Add(del);
        }

        void sectsDrawItem(object sender, DrawItemEventArgs e)
        {
            if (e.Index > sects.Items.Count - 1) return;
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                e.Graphics.FillRectangle(Brushes.DimGray, e.Bounds);
            else
                e.Graphics.FillRectangle(Brushes.Black, e.Bounds);

            e.Graphics.DrawString(e.Index.ToString("x2"), sects.Font, Brushes.White, 0, e.Bounds.Y);
            e.Graphics.DrawString(sects.GetItemText(sects.Items[e.Index]), sects.Font, Brushes.White, 25, e.Bounds.Y);
        }

        void Delete(object sender, EventArgs e)
        {
            if (sects.SelectedItem != null)
            {
                (sects.DataSource as BindingList<T>).Remove(sects.SelectedItem as T);
            }
        }

        void Add(object sender, EventArgs e)
        {
            (sects.DataSource as BindingList<T>).Add(new T());
        }

        protected override void RefreshData()
        {
            this.Controls.Clear();
            int propCount = 0;
            foreach (PropertyInfo i in Object.GetType().GetProperties())
                if (i.DeclaringType == Object.GetType() && i.CanRead && i.CanWrite && i.Name != "Item") propCount++;
            if (propCount != 0)
            {
                SplitContainer sCan = new SplitContainer();
                sCan.Orientation = Orientation.Horizontal;
                sCan.Dock = DockStyle.Fill;

                PropertyEditor editor = new PropertyEditor();
                editor.Object = Object;
                editor.Dock = DockStyle.Fill;
                sCan.Panel1.Controls.Add(editor);

                sCan.Panel2.Controls.Add(can);
                this.Controls.Add(sCan);
                can.SplitterDistance = 100;
                sCan.SplitterDistance = 150;
            }
            else
            {
                this.Controls.Add(can);
                can.SplitterDistance = 100;
            }

            CollectionLinkingBindingList<T> bList = new CollectionLinkingBindingList<T>(Object as IList<T>);
            sects.DisplayMember = n;
            sects.DataSource = bList;
            etr.Object = null;
            etr.Visible = false;
        }

        protected virtual void ItemChanged(object sender, EventArgs e)
        {
            if (sects.SelectedItem != null)
            {
                (etr.GetType().GetProperty("Actions").GetGetMethod().Invoke(etr, null) as List<PropertyAction>).Clear();
                (etr.GetType().GetProperty("Actions").GetGetMethod().Invoke(etr, null) as List<PropertyAction>).AddRange(acts);

                etr.Visible = false;
                etr.Object = sects.SelectedItem as T;
                etr.Visible = true;
            }
        }

        private void RefreshText(object sender, EventArgs e)
        {
            (sects.DataSource as BindingList<T>).ResetBindings();
        }
    }
}
